#============================================================
#    Bottom Panel
#============================================================
# - datetime: 2022-09-30 21:48:58
#============================================================
@tool
extends Control


##  点击重新加载按钮，如果是这个场景被修改了，则由于 Godot 的原因，这个不会生效了
signal reloaded


const ITEM_SCENE = preload("item/item.tscn")
const ItemMenu = preload("item_menu.gd")


@onready 
var tree : Tree = %tree
@onready 
var item_container = %item_container
var editor_interface : EditorInterface
@onready 
var reload_button : Button = %reload_button
@onready 
var location_button := %location_button as Button
@onready 
var item_menu := %item_menu as ItemMenu
@onready 
var save_data_timer := %save_data_timer as Timer
@onready
var util = CollectionPanelUtils.instance()
@onready 
var sort_button: Button = %sort_button
var item_type_list := ["All"]


class PathInfo:
	
	const ITEM_SCENE = preload("item/item.tscn")
	const ITEM_SCRIPT = preload("item/item.gd")
	
	var path: String
	var item: ITEM_SCRIPT
	var type: String
	var resource
	var filename : String
	
	func is_file():
		return type != "Folder"
	
	func _init(editor_interface: EditorInterface, _path: String):
		self.path = _path.trim_suffix("/")
		var file_sys_dir : EditorFileSystemDirectory
		if FileAccess.file_exists(path):
			type = "File"
			filename = path.get_file()
			file_sys_dir = editor_interface.get_resource_filesystem().get_filesystem_path(path.get_base_dir())
			var idx = file_sys_dir.find_file_index(path.get_file())
			type = file_sys_dir.get_file_type(idx)
			resource = load(path)
			if resource is Script:
				type = "Script"
		else:
			file_sys_dir = editor_interface.get_resource_filesystem().get_filesystem_path(path)
			type = "Folder"
		# 加载图标
		var texture = editor_interface.get_base_control().get_theme_icon(type, "EditorIcons")
		if texture == null:
			texture = load("res://icon.svg")
		item = ITEM_SCENE.instantiate() as ITEM_SCRIPT
		item.set_texture(texture)
		item.set_path( path )
	

## 保存数据存储到的文件路径
var data_file_path := get_script().resource_path.get_base_dir().path_join("data.gdata") as String
## 路径对应的路径信息
var path_to_info_map := {}
## 展示的类型
var show_type : String = "All"
## 当前选中的 Item
var selected_item :
	set(v):
		selected_item = v
		var disable = (selected_item == null)
		item_menu.set_item_disabled_by_name( ItemMenu.MENU_DATA.edit, disable )
		item_menu.set_item_disabled_by_name( ItemMenu.MENU_DATA.open_explorer, disable )
		item_menu.set_item_disabled_by_name( ItemMenu.MENU_DATA.remove, disable )
		
		if selected_item:
			
			if (get_item_path_info(selected_item).resource == null 
				or get_item_path_info(selected_item).type == "Folder"
			):
				item_menu.set_item_disabled_by_name( ItemMenu.MENU_DATA.edit, true)


#============================================================
#  SetGet
#============================================================
func get_editor_interface() -> EditorInterface:
	return editor_interface

func get_icon(icon_name:String) -> Texture:
	return get_editor_interface().get_base_control().get_theme_icon(icon_name, "EditorIcons")

func get_path_info(path: String) -> PathInfo:
	return path_to_info_map.get(path) as PathInfo

func get_item_path_info(item: Node) -> PathInfo:
	return get_path_info(item.path) as PathInfo

func get_select_item_path_info() -> PathInfo:
	if selected_item:
		return get_item_path_info(selected_item)
	return null


#============================================================
#  内置
#============================================================
func _enter_tree():
	init_data.call_deferred()

func _exit_tree():
	save_data()


#============================================================
#  自定义
#============================================================
func init_data():
	editor_interface = EditorPlugin.new().get_editor_interface()
	
	while true:
		var o = get_editor_interface().get_resource_filesystem().get_filesystem_path("res://")
		if o != null:
			break
		else:
			await get_tree().process_frame
	
	await get_tree().process_frame
	
	# 添加类别
	tree.clear_items()
	tree.add_type("All")
	
	# 加载数据
	if FileAccess.file_exists(data_file_path):
		load_data()
	# 重新加载
	reload_button.icon = get_icon("Reload")
	reload_button.pressed.connect(func(): self.reloaded.emit() )
	# 定位位置
	location_button.icon = get_icon("TransitionSync")
	location_button.pressed.connect(func():
		# 判断当前所在编辑的视图
		var type = self.util.get_main_screen_editor()
		if type == "Script":
			var current_script_path = get_editor_interface().get_script_editor().get_current_script().resource_path
			get_editor_interface().get_file_system_dock().navigate_to_path(current_script_path)
		elif type in ["2D", "3D"]:
			var root = get_editor_interface().get_edited_scene_root()
			if root:
				var path = root.scene_file_path
				get_editor_interface().get_file_system_dock().navigate_to_path(path)
			else:
				printerr("没有正在编辑的场景，定位失败")
	)
	# 排序
	sort_button.icon = get_icon("Sort")
	sort_button.toggled.connect(func(button_pressed):
		for child in item_container.get_children():
			item_container.remove_child(child)
		if button_pressed:
			# 重新排序
			var list = path_to_info_map.values()
			list.sort_custom(func(a: PathInfo, b: PathInfo):
				return a.filename.to_lower() < b.filename.to_lower()
			)
			for info in list:
				item_container.add_child(info.item)
			
		else:
			# 还原顺序
			for path in path_to_info_map:
				item_container.add_child(path_to_info_map[path].item)
			
	)
	sort_button.button_pressed = true
	await get_tree().process_frame
	sort_button.toggled.emit(true)

## 加载数据
func load_data():
	var file = FileAccess.open(data_file_path, FileAccess.READ)
	if file:
		print("【collection_panel】加载数据")
		var map = file.get_var() as Dictionary
		for path in map:
			add_item(path, false)
	else:
		printerr("【collection_panel】打开文件失败：", FileAccess.get_open_error())

## 保存数据
func save_data():
	var file = FileAccess.open(data_file_path, FileAccess.WRITE)
	if file:
		var dup = path_to_info_map.duplicate()
		for path in dup:
			dup[path] = null
		file.store_var(dup)
		file = null
		print("【collection_panel】已保存数据：", data_file_path)
	else:
		printerr("【collection_panel】保存文件失败：", FileAccess.get_open_error())


## 添加 Item。[code]path[/code] 为添加的路径，[code]auto_save[/code] 是否自动保存数据
func add_item(path: String, auto_save: bool = true):
	if (FileAccess.file_exists(path) or DirAccess.dir_exists_absolute(path)):
		if not path_to_info_map.has(path):
			var info = PathInfo.new(get_editor_interface(), path)
			path_to_info_map[info.path] = info
			add_item_node(info)
			if not item_type_list.has(info.type):
				item_type_list.append(info.type)
				tree.add_type(info.type)
				print("---- > ", info.type)
			
			if sort_button.button_pressed:
				var list = path_to_info_map.values()
				list.sort_custom(func(a: PathInfo, b: PathInfo):
					return a.filename.to_lower() < b.filename.to_lower()
				)
				var index = list.find(info)
				item_container.move_child(info.item, index+1)
			
			# 添加后等待几秒间隔进行保存，以防止一次添加多个时保存次数过多
			if auto_save:
				save_data_timer.stop()
				save_data_timer.start()
		else:
			printerr("已添加这个文件")
	else:
		printerr("没有这个文件：file = ", path)


## 添加 Item 节点
func add_item_node(info: PathInfo):
	var item = info.item
	item_container.add_child(item)
	# 连接信号
	item.double_clicked.connect(func():
		# 双加编辑文件
		if info.is_file() and info.resource != null:
			# 编辑资源
			if info.resource is PackedScene:
				get_editor_interface().open_scene_from_path( info.path )
			else:
				get_editor_interface().edit_resource( info.resource )
		else:
			# 定位到文件位置
			get_editor_interface().get_file_system_dock().navigate_to_path(info.path)
	)
	item.selected.connect(func(): self.selected_item = item )
	item.deselected.connect(func(): 
		await get_tree().process_frame
		self.selected_item = null 
	)
	# 右键点击
	item.right_clicked.connect(func():
		var p = Rect2(get_global_mouse_position(), self.item_menu.size)
		var last_selected_item = self.selected_item
		self.item_menu.popup(p)
		self.selected_item = item
		await self.item_menu.visibility_changed
		self.selected_item = item
	)
	update_item_visible(info)


## 移出这个项
func remove_item(path:String):
	if path_to_info_map.has(path):
		var info = get_path_info(path) as PathInfo
		info.item.queue_free()
		path_to_info_map.erase(path)
		save_data_timer.stop()
		save_data_timer.start()
		print("已移除：", path)
	else:
		printerr("没有这个路径：", path)


func update_item_visible(info: PathInfo):
	if show_type != "All":
		info.item.visible = (info.type == show_type)
	else:
		info.item.visible = true


#============================================================
#  连接信号
#============================================================
func _on_tree_selected_item(item: TreeItem, data: Dictionary):
	show_type = ""
	if data.has("type"):
		var info : PathInfo
		show_type = data["type"] as String
		if show_type == "All":
			# 显示全部
			for path in path_to_info_map:
				info = get_path_info(path) as PathInfo
				info.item.visible = true
		else:
			# 展示要显示的类型
			for path in path_to_info_map:
				info = get_path_info(path) as PathInfo
				update_item_visible(info)


func _on_item_menu_clicked_item(id:int, item_name:String):
	if selected_item == null:
		print('没有选中 Item')
		return 
	var path := get_select_item_path_info().path as String
	match item_name:
		ItemMenu.MENU_DATA.edit:
			var resource = get_item_path_info(selected_item).resource
			# 编辑这个资源
			if resource:
				get_editor_interface().edit_resource(resource)
			else:
				printerr('这个 Item 没有资源')
			print("【collection_panel】编辑资源：", path)
			
		ItemMenu.MENU_DATA.open_explorer:
			# 打开文件夹位置
			if get_select_item_path_info().is_file():
				path = path.get_base_dir()
			path = ProjectSettings.globalize_path(path)
			OS.shell_open(path)
			print("【collection_panel】打开文件位置：", path)
			
		ItemMenu.MENU_DATA.remove:
			# 移除掉这个路径
			remove_item(path)
			print("【collection_panel】移除资源：", path)
		
		_:
			print("点击菜单：", item_name)


func _on_item_menu_popup_hide():
	self.selected_item = null


